package com.wkr.jdbc.test03;

import java.io.InputStream;
import java.lang.reflect.Field;
import java.sql.*;
import java.util.*;

import com.jdbc.test02.NewInstance;

public class MyConnect<T> {
	Scanner sc = new Scanner(System.in);
	/**
	 * 数据库表字段数目
	 */
	static int fieldCount = 0;
	/**
	 * 数据库表字段名
	 */
	List<String> fieldName = new ArrayList<String>();
	/**
	 * 添加字段名的标志
	 */
	int addFieldNameOfFlag = 0;
	
	/**
	 * 获取驱动
	 * @return
	 * @throws Exception
	 */
	public Connection connectWithData() throws Exception {
		InputStream is = MyConnect.class.getClassLoader().getResourceAsStream("data.properties");
		// 创建Porperties属性类
		Properties prop = new Properties();
		// 加载数据库配置文件流
		prop.load(is);
		String strDirverName = prop.getProperty("dirverName");
		Class.forName(strDirverName);
		// (2) 获取数据库连接对象
		// 1521 数据库服务器监听的端口号；orcl：数据库名数据实例名
		String url = prop.getProperty("url");// 数据库连接各个属性 url连接串  解析连接串：@前面固定写法；@后面是数据库服务器的ip地址或主机名；
		// 用户名
		String name = prop.getProperty("name");
		// 密码
		String psw = prop.getProperty("psw");
		// 从驱动管理类中获取指定参数的数据库连接对象
		Connection conn = null;
		try {
			conn = DriverManager.getConnection(url,name,psw);
		} catch (Exception e) {
			System.out.println("密码错误！");
		}
		return conn;//返回数据库连接对象
	}
	
	/**
	 * @功能描述：得到执行器并执行查询
	 */
	@SuppressWarnings("hiding")
	public<T> List<T> GetData(Class<T> clazz, String strSql) throws Exception{
		List<T> list = null;
		//通过数据库连接对象得到执行器
		Statement st = this.connectWithData().createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
		//执行器执行查询语句进行查询
		ResultSet rs = st.executeQuery(strSql);
		list  = this.returnList(rs, clazz);
		System.out.println("转存结束！");
		rs.close();//关闭资源
		this.connectWithData().close();//释放连接对象
		return list;
	}
	/**
	 * @功能描述：将结果集内的数据转存到集合内
	 * @param rs
	 * @param clazz
	 * @return
	 */
	@SuppressWarnings("hiding")
	public  <T> List<T> returnList (ResultSet rs, Class<T> clazz){
		List<T> list = new ArrayList<>();
		try {
			ResultSetMetaData rsmd = rs.getMetaData();//获取字段列信息
			fieldCount = rsmd.getColumnCount();//获得字段数
			while(rs.next()) {
				T t = clazz.newInstance();//实例传进来类的对象
				for(int i = 1; i <= fieldCount; i++) {
					String rowName = rsmd.getColumnName(i);//获得字段名
					if(addFieldNameOfFlag == 0) {
						fieldName.add(rowName);
					}
					Field field = clazz.getDeclaredField(rowName.toLowerCase());
					field.setAccessible(true);
					field.set(t, convertDataType(rs.getObject(rowName), field.getType().getName()));
				}
				addFieldNameOfFlag = 1;
				list.add(t);
			}//此时所有数据已转存到List中 不再不要执行器 会占用资源 可以关闭
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		};
		return list;
		
	}
	
	
	/**
	 * @功能描述：将集合内的数据输出
	 * @throws Exception
	 */
	public void showData() throws Exception {
		String strSql = "SELECT *FROM departments e";
		List<departments> data = this.GetData(departments.class, strSql);//数据集合
		for (String string : fieldName) {
			System.out.format("%25s", string);
		}
		System.out.println();
		for (departments t : data) {
			t.show();
		}
		System.out.println("结束");
	}
	
	/**
	 * @功能描述：主函数驱动
	 * @param args
	 */
	public static void main(String[] args){
		
		try {
			NewInstance.newInstance(MyConnect.class).showData();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * @功能描述：数据转换，将数据库数据类型转换为Java数据类型
	 * @param obj
	 * @param strDesDataType
	 * @return obj
	 */
	private static Object convertDataType(Object obj, String strDesDataType) {
		// 返回值类型
		Object obj_re = null;
		if (obj != null) {
			// 将不能映射为java基本类型的JDBC数据类型转为与之对应的java类型
			// 类型转换
			switch (strDesDataType.trim()) {
			case "java.lang.Long":
				obj_re = Long.parseLong(obj.toString());
				break;
			case "java.lang.Double":
				obj_re = Double.parseDouble(obj.toString());
				break;
			// ... 追加补充其他类型的转换
			// 不需要进行转换的数据类型直接返回即可
			default:
				obj_re = obj;
			}
		}
		// 返回值
		return obj_re;
	}
}
